/*
#
#  Copyright 2011 Matthew Jannace
#
#  This file is part of RoboCode BlackHoleAgent
#
#  RoboCode BlackHoleAgent is free software: you can redistribute it and/or
#  modify it under the terms of the GNU General Public License as
#  published by the Free Software Foundation, either version 3 of the
#  License, or (at your option) any later version.
#
#  RoboCode BlackHoleAgent is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
#  General Public License for more details.
#
#  You should have received a copy of the GNU General Public License
#  along with RoboCode BlackHoleAgent. If not, see
#  <http://www.gnu.org/licenses/>.
#
 */
package com.jannaceltd.TeamBlackHoleBeer.Modules.Targeting.TargetingMethods;

import com.jannaceltd.TeamBlackHoleBeer.BlackHole_Abstract;
import com.jannaceltd.TeamBlackHoleBeer.Modules.Targeting.Targeting;
import java.util.ArrayList;
import java.util.List;
import robocode.util.Utils;

/**
 * Class that Performs Exact Guess Factor Targeting
 * @author Matthew Jannace <mjannace@gmail.com>
 * @version 1.0
 *
 * Based on the GuessFactor Targeting Tutorial
 * @link http://robowiki.net/wiki/GuessFactor_Targeting_Tutorial
 */
public class GuessFactorTargeting {

    private BlackHole_Abstract Agent = null;
    private Targeting gun = null;
    private double firePower = 0;
    //int[][] stats = new int[13][31]; // onScannedRobot can scan up to 1200px, so there are only 13.
    private static int[] stats = new int[31]; // 31 is the number of unique GuessFactors we're using
    // Note: this must be odd number so we can get
    // GuessFactor 0 at middle.
    private int direction = 1;
    /**
     * List to track Waves of Bullets Fired for tracking and guess factor adjustments
     */
    protected List<WaveBullet> waves = new ArrayList<WaveBullet>();
    private WaveBullet newWave = null;
    private double gunAdjust = 0.0;

    /**
     * Creates a new GuessFactorTargeting object
     * @param Agent
     * @param gun
     */
    public GuessFactorTargeting(BlackHole_Abstract Agent, Targeting gun) {
        this.Agent = Agent;
        this.gun = gun;
    }

    /**
     * Takes A Guess Factor Targeting Shot
     */
    public void doGuessFactorTargeting() {

        // Enemy absolute bearing, you can use your one if you already declare it.
        //double absBearing = Utils.normalAbsoluteAngle(Agent.getHeadingRadians() + Agent.target.getBearingRadians());
        double absBearing = Agent.getHeadingRadians() + Agent.target.getBearingRadians();
        double relativeBearing = Agent.target.getBearingRadians();

        // find our enemy's location:
        double ex = Agent.target.getX();
        double ey = Agent.target.getY();
        /*
        System.out.println("\n"
        + "absBearing = " + absBearing + ",\n"
        + "relativeBearing = " + relativeBearing + ",\n"
        + "ex = " + ex + ",\n"
        + "ey = " + ey);
         */
        // Let's process the waves now:
        for (int i = 0; i < waves.size(); i++) {
            WaveBullet currentWave = waves.get(i);
            if (currentWave.checkHit(ex, ey, Agent.getTime())) {
                waves.remove(currentWave);
                i--;
            }
        }

        double distanceToTarget = Agent.getPos().distance(Agent.target.getPos());
        firePower = Math.min(3, Math.max(Agent.getEnergy() / 6d, 1300d / distanceToTarget));
        // don't try to figure out the direction they're moving
        // they're not moving, just use the direction we had before
        if (Agent.target.getVelocity() != 0) {
            if (Math.sin(Agent.target.getHeadingRadians() - absBearing) * Agent.target.getVelocity() < 0) {
                direction = -1;
            } else {
                direction = 1;
            }
        }
        int[] currentStats = stats;
        //int[] currentStats = stats[(int) (Agent.target.getDistance() / 100)]; // It doesn't look silly now!

        newWave = new WaveBullet(Agent.getX(), Agent.getY(), absBearing, relativeBearing, firePower, direction, Agent.getTime(), currentStats);

        int bestindex = 15;	// initialize it to be in the middle, guessfactor 0.
        for (int i = 0; i < 31; i++) {
            if (currentStats[bestindex] < currentStats[i]) {
                bestindex = i;
            }
        }

        // this should do the opposite of the math in the WaveBullet:
        double guessfactor = (double) (bestindex - (stats.length - 1) / 2) / ((stats.length - 1) / 2);
        double angleOffset = direction * guessfactor * newWave.maxEscapeAngle();

        gunAdjust = Utils.normalRelativeAngle(absBearing - Agent.getGunHeadingRadians() + angleOffset);
        Agent.setTurnGunRightRadians(gunAdjust);

        /*
        System.out.println("\n"
        + "gunAdjust = " + gunAdjust);
         */
        //+ "gunAdjust = " + gunAdjust + " = " + Agent.getGunHeadingRadians() + " - " + relativeBearing);//+ " + " + angleOffset);
        //+ "gunAdjust2 = " + (Utils.normalRelativeAngle(MathUtils.calcAngle(Agent.target.getPos(), Agent.getPos()) - Agent.getGunHeadingRadians())) + " + " + angleOffset);//+ angleOffset);


        if (Agent.getGunHeat() == 0 && gunAdjust < Math.atan2(9, Agent.target.getDistance()) && Agent.setFireBullet(firePower) != null) {
            waves.add(newWave);
        }
    }

    /**
     * Gets the Waves of bullets shot
     * @return waves
     */
    public List<WaveBullet> getWaves() {
        return waves;
    }
}
